/**
 * Tables.java
 * @author: liuex
 * 2008-3-5 ����08:06:33
 *
 * note: 
 */
package org.lex.swing.table;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Comparator;
import java.util.Map;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;

import org.lex.swing.ActionBuilder;
import org.lex.swing.Swings;
import org.lex.utils.Pair;


public class TableHelper {
	/***************************************************************************
	 * Utilities for create a read-only TableModel from a Map
	 **************************************************************************/
	public static <K, V> TableModel createModel(Map<K, V> map) {
		return TableHelper.createModel(map, MapTableModel.FIRST_COLUMN, MapTableModel.SECOND_COLUMN);
	}

	public static <K, V> TableModel createModel(Map<K, V> map, String firstColumn, String secondColumn) {
		return new MapTableModel<K, V>(map, firstColumn, secondColumn);
	}

	public static <K, V> TableModel createModel(Map<K, V> map, Comparator<K> key) {
		return new MapTableModel<K, V>(map, MapTableModel.FIRST_COLUMN, MapTableModel.SECOND_COLUMN, key, null);
	}

	public static <K, V> TableModel createModel(Map<K, V> map, Comparator<K> key, Comparator<V> value) {
		return new MapTableModel<K, V>(map, MapTableModel.FIRST_COLUMN, MapTableModel.SECOND_COLUMN, key, value);
	}

	public static <K, V> TableModel createModel(Map<K, V> map, String firstColumn, String secondColumn, Comparator<K> key, Comparator<V> value) {
		return new MapTableModel<K, V>(map, firstColumn, secondColumn, key, value);
	}

	/**
	 * ����һ���˷��ھ��?������������
	 * 
	 * @param rowCount
	 * @param columnCount
	 * @return
	 */
	public static TableModel createMultiplicationTableModel(int rowCount, int columnCount) {
		Object[][] data = new Integer[rowCount][columnCount];
		Object[] names = new String[columnCount];
		for (int column = 1; column <= columnCount; column++) {
			for (int row = 1; row <= rowCount; row++) {
				data[row - 1][column - 1] = row * column;
			}
			names[column - 1] = Integer.toString(column);
		}
		return new DefaultTableModel(data, names);
	}

	/***************************************************************************
	 * Utilities for auto-resizing table column width
	 **************************************************************************/
	private static final String TABLE_COLUMN_AUTO_RESIZER_KEY = TableHelper.class.getName() + ".tableColumnAutoResizer";

	/**
	 * @param table
	 * @param b
	 */
	public static void setAutoResizeEnabled(JTable table, boolean b) {
		Object o = table.getClientProperty(TABLE_COLUMN_AUTO_RESIZER_KEY);
		TableColumnResizer resizer = null;
		if (o instanceof TableColumnResizer)
			resizer = (TableColumnResizer) o;
		if (b) {
			// enable
			if (null == resizer) {
				resizer = new TableColumnResizer(table);
				table.putClientProperty(TABLE_COLUMN_AUTO_RESIZER_KEY, resizer);
			}
			if (false == resizer.isEnabled()) {
				resizer.setEnabled(true);
			}
		} else {
			// disable
			if (null != resizer)
				resizer.setEnabled(false);
		}
	}

	public static TableColumnResizer getAutoResizer(JTable table) {
		Pair<Boolean, TableColumnResizer> p = hasAutoResizer(table);
		TableColumnResizer resizer = null;
		if (false == p.first()) {
			resizer = new TableColumnResizer(table);
			table.putClientProperty(TABLE_COLUMN_AUTO_RESIZER_KEY, resizer);
		} else {
			resizer = p.second();
		}
		return resizer;
	}

	/**
	 * @param table
	 * @return <Has a resizer, the resizer>
	 */
	public static Pair<Boolean, TableColumnResizer> hasAutoResizer(JTable table) {
		Object o = table.getClientProperty(TABLE_COLUMN_AUTO_RESIZER_KEY);
		TableColumnResizer resizer = null;
		boolean has = false;
		if (o instanceof TableColumnResizer) {
			resizer = (TableColumnResizer) o;
			has = true;
		}
		return Pair.wrap(has, resizer);
	}

	/***************************************************************************
	 * Utilities for adding a PopupMenu to JTableHeader
	 **************************************************************************/
	public static void test(final JTable table) {
		final JPopupMenu popup = new JPopupMenu();
		popup.add(TableHelper.createAutoResizeMenuItem(table));
		popup.add(new ShowGridMenu(table));
		JTableHeader header = table.getTableHeader();
		header.setComponentPopupMenu(popup);
		// change popup if "tableHeader" changed
		table.addPropertyChangeListener("tableHeader", new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent e) {
				if ("tableHeader".equals(e.getPropertyName()))
					((JTableHeader) e.getNewValue()).setComponentPopupMenu(popup);
			}
		});
	}

	public static JCheckBoxMenuItem createAutoResizeMenuItem(final JTable table) {
		final int modeBak = table.getAutoResizeMode();
		final TableColumnResizer resizer = getAutoResizer(table);
		final ActionBuilder a = new ActionBuilder("Auto Resize");
		a.setSelected(resizer.isEnabled());
		a.setActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				boolean auto = a.isSelected();
				if (true == auto)
					table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
				else
					table.setAutoResizeMode(modeBak);
				resizer.setEnabled(auto);
			}
		});
		return new JCheckBoxMenuItem(a);
	}

	private static class ShowGridMenu extends JMenu implements ActionListener {
		private static final String BOTH = "Both";
		private static final String HORIZONTAL = "Horizontal";
		private static final String VERTICAL = "Vertical";
		private final JTable table;
		private final JCheckBoxMenuItem both;
		private final JCheckBoxMenuItem horizontal;
		private final JCheckBoxMenuItem vertical;

		ShowGridMenu(final JTable table) {
			this.table = table;
			this.setText("Show Grid");
			this.both = this.createMenuItem(BOTH);
			this.horizontal = this.createMenuItem(HORIZONTAL);
			this.vertical = this.createMenuItem(VERTICAL);
			// ----------------------------------------------
			boolean h = table.getShowHorizontalLines();
			this.horizontal.setSelected(h);
			boolean v = table.getShowVerticalLines();
			this.vertical.setSelected(v);
			this.both.setSelected(h && v);
			// ---------------------------------------------
			this.add(both);
			this.add(horizontal);
			this.add(vertical);
		}

		private JCheckBoxMenuItem createMenuItem(String name) {
			JCheckBoxMenuItem mi = new JCheckBoxMenuItem();
			mi.setText(name);
			mi.setActionCommand(name);
			mi.addActionListener(this);
			return mi;
		}

		public void actionPerformed(ActionEvent e) {
			String ac = e.getActionCommand();
			if (BOTH == ac) {
				boolean select = both.isSelected();
				Swings.setSelected(select, horizontal, vertical);
				table.setShowGrid(select);
			} else if (HORIZONTAL == ac) {
				boolean select = horizontal.isSelected();
				if (false == select)
					both.setSelected(false);
				else if (true == vertical.isSelected())
					both.setSelected(true);
				table.setShowHorizontalLines(select);
			} else if (VERTICAL == ac) {
				boolean select = vertical.isSelected();
				if (false == select)
					both.setSelected(false);
				else if (true == horizontal.isSelected())
					both.setSelected(true);
				table.setShowVerticalLines(select);
			}
		}
	}
}
